package com.liuqing.www.手机技术.图片处理;

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/**http://www.punypng.com/
 * http://www.ismyway.com/png/png-struct1.htm
 * Name: TEAM ARN
Serial: 897L-NPES-LFHS-623W
 * 0xffffffff每个f4位，一个byte8位，2个f为1byte
 * png图片分析 8字节
 * 文件头：十进制数 137 80 78 71 13 10 26 10 
         十六进制数 89 50 4E 47 0D 0A 1A 0A 
   数据块：
	PNG文件中，每个数据块由4个部分组成，如下：
	名称  字节数  说明  
	Length (长度)  4字节  指定数据块中数据域的长度，其长度不超过(231－1)字节  
	Chunk Type Code (数据块类型码)  4字节  数据块类型码由ASCII字母(A-Z和a-z)组成  
	Chunk Data (数据块数据)  可变长度  存储按照Chunk Type Code指定的数据  
	CRC (循环冗余检测)  4字节  存储用来检测是否有错误的循环冗余码  
		IHDR 第一块 只能必须一个共13字节
				Width  4 bytes  图像宽度，以像素为单位  
				Height  4 bytes  图像高度，以像素为单位  
				Bit depth  1 byte  图像深度： 
										索引彩色图像：1，2，4或8 
										灰度图像：1，2，4，8或16 
										真彩色图像：8或16  
				ColorType  1 byte  颜色类型：
										0：灰度图像, 1，2，4，8或16 
										2：真彩色图像，8或16 
										3：索引彩色图像，1，2，4或8 
										4：带α通道数据的灰度图像，8或16 
										6：带α通道数据的真彩色图像，8或16  
				Compression method  1 byte  压缩方法(LZ77派生算法)  
				Filter method  1 byte  滤波器方法  
				Interlace method  1 byte  隔行扫描方法：
											0：非隔行扫描 
											1： Adam7(由Adam M. Costello开发的7遍隔行扫描方法) 
		IEND  图像结束数据IEND(image trailer chunk)：它用来标记PNG文件或者数据流已经结束，并且必须要放在文件的尾部。
			  如果我们仔细观察PNG文件，我们会发现，文件的结尾12个字符看起来总应该是这样的：
			  00 00 00 00 49 45 4E 44 AE 42 60 82
			  PLTE

		PLTE(palette chunk)包含有与索引彩色图像(indexed-color image)相关的彩色变换数据，它仅与索引彩色图像有关，而且要放在图像数据块(image data chunk)之前。

			PLTE数据块是定义图像的调色板信息，PLTE可以包含1~256个调色板信息，每一个调色板信息由3个字节组成：
			颜色
			 字节
		 	意义 
			Red
			 1 byte
			 0 = 黑色, 255 = 红
			Green
			 1 byte
			 0 = 黑色, 255 = 绿色 
			Blue
			 1 byte
			 0 = 黑色, 255 = 蓝色 
			 
			因此，调色板的长度应该是3的倍数，否则，这将是一个非法的调色板。
			
			对于索引图像，调色板信息是必须的，调色板的颜色索引从0开始编号，然后是1、2……，调色板的颜色数不能超过色深中规定的颜色数（如图像色深为4的时候，调色板中的颜色数不可以超过2^4=16），否则，这将导致PNG图像不合法。
			
			真彩色图像和带α通道数据的真彩色图像也可以有调色板数据块，目的是便于非真彩色显示程序用它来量化图像数据，从而显示该图像。

		IDAT

			图像数据块IDAT(image data chunk)：它存储实际的数据，在数据流中可包含多个连续顺序的图像数据块。
			
			IDAT存放着图像真正的数据信息，因此，如果能够了解IDAT的结构，我们就可以很方便的生成PNG图像。

	关键数据库块：IHDR、PLTE 、IDAT 、END 

（文件头）8个字节-》IHDR长度说明（4字节）+IHDR类型（4字节）+IDAT（13字节）+CRC校验 （4字节）
	-》PLTE长度说明（4字节）+PLTE类型（4字节）+PLTE（长度指定字节）+CRC校验 （4字节）
	-》IDAT长度说明（4字节）+IDAT类型（4字节）+IDAT（长度指定字节）+IDAT校验 （4字节）
	-》END 12字节

 * @author 韩世超
 *
 */
public class 图片压缩 {
	public static void main(String[] args) {
		try {
			compression.compression1("F:/素材/drugs/2009090720171520817.png");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
class compression{
	public static void compression1(String path) throws Exception{//舍去辅助数据块的压缩
		FileInputStream fi=new FileInputStream("F:/复件 Big.png");
		FileOutputStream nowfi=new 	FileOutputStream ("F:/Big1.png");
		byte b[]=new byte[1024*10];
		DataInputStream dis=new DataInputStream(fi);
		dis.read(b,0,33);//读取头8字节,ihead 8+13+4
		nowfi.write(b,0,33);//写完头
		read(dis,nowfi,b);
		fi.close();
		nowfi.flush();
		nowfi.close();
		
		
	}
	public static void read(DataInputStream dis,FileOutputStream nowfi,byte b[])throws Exception{
		if(dis.available()<=12){
//			dis.read(b,0,12);
			nowfi.write(IEND);
			System.out.println("达到结尾!!!"+dis.available());
			return ;
		}
		//(b[0]&0xff)<<24|(b[1]&0xff)<<16|(b[2]&0xff)<<8|(b[3]&0xff)
		int i=dis.readInt();//读取4字节为块的长度或者
		if(i<=0){
			System.out.println("长度达到结尾!!!"+dis.available());
			return ;
		}
		System.out.println(i);
		dis.read(b,0,4);//读取四字节为块的类型
		if((IPLTE[0]==b[0]&&IPLTE[1]==b[1]&&IPLTE[2]==b[2]&&IPLTE[3]==b[3])||
				(IDAT[0]==b[0]&&IDAT[1]==b[1]&&IDAT[2]==b[2]&&IDAT[3]==b[3])
				){//读到了IPLTE
			System.out.println("读到IPLTE或IDAT。。。");
			nowfi.write(inttobyte(i));//写头
			nowfi.write(b,0,4);//写类型
			dis.read(b,0,i);//读数据
			nowfi.write(b,0,i);//写完头
			dis.read(b,0,4);//读CRC
			nowfi.write(b,0,4);//写CRC
			
		}else{
			System.out.println("读到废物数据");
			dis.skip(i+4);//跳过数据以及crc
		}
		read(dis,nowfi,b);
		
	}
	static byte[] inttobyte(int i){
		byte[] b=new byte[4];
		b[0]=(byte)(i>>24);
		b[1]=(byte)(i>>16);
		b[2]=(byte)(i>>8);
		b[3]=(byte)(i&0xff);
		return b;
	}
	static int bytetoint(byte[] b){	
		return (b[0]&0xff)<<24|(b[1]&0xff)<<16|(b[2]&0xff)<<8|(b[3]&0xff);
	}
	  public static byte[] FileHEAD = {//png文件标示8字节
          (byte) 0x89, (byte) 0x50,
          (byte) 0x4E, (byte) 0x47,
          (byte) 0x0D, (byte) 0x0A,
          (byte) 0x1A, (byte) 0x0A,
	  };
	  public static byte[] IHEAD = {//IHEAD大小4字节、类型4字节
          (byte) 0x00, (byte) 0x00,
          (byte) 0x00, (byte) 0x0D,//长度为13字节
          (byte) 0x49, (byte) 0x48,
          (byte) 0x44, (byte) 0x52,//IHEAD标示符
	  };
	  public static byte[] IPLTE = {//IPLTE标识符   
          (byte) 0x50, (byte) 0x4C,
          (byte) 0x54, (byte) 0x45,
	  };
	  public static byte[] IDAT = {//IDATE标识符   
          (byte) 0x49, (byte) 0x44,
          (byte) 0x41, (byte) 0x54,
	  };
	  public static byte[] IEND = {//固定12字节png文件结束标示
          (byte) 0x00, (byte) 0x00,
          (byte) 0x00, (byte) 0x00,
          (byte) 0x49, (byte) 0x45,
          (byte) 0x4E, (byte) 0x44,
          (byte) 0xAE, (byte) 0x42,
          (byte) 0x60, (byte) 0x82
};
}
